[iOS]Mintを使ってプロジェクトごとのSwift製CLIツールのパッケージ管理を行う
Homebrewを使っていたのですが、Swift製のコマンドラインツールのSwiftLintやSwiftGen、Carthageなどを使う時にプロジェクトごとにこれらのツールのバージョン管理うまいことやりたいと思いました。身近な例だとBundlerがやっていることをSwift製のパッケージ管理でも行いたいです。今回はせっかくなので自分の環境が原因で手間取ったSwiftLintをローカルでMintで入れてみてプロジェクトで使用してみるまでを記事にします。
インストールとセットアップ
リポジトリは以下です。
インストール方法はREADME.md色々あるので手元の環境に合わせてください。今回はcloneしてきてビルドしました。
$ git clone https://github.com/yonaskolb/Mint.git $ cd Mint $ swift run mint install yonaskolb/mint
記事執筆時のバージョンは以下です。
$ mint version Version: 0.14.2
makeでのインストールに11/1時点で失敗する
インストール方法は複数ありますが、makeでイントールしようとするとpathが間違っているというエラーが出てきます。
91%: Copy Mint.swiftsourceinfo (x86_64) 91%: Copy Mint.swiftsourceinfo (x86_64) 91%: Copy Mint.swiftmodule (x86_64) 98%: Generate mint.dSYM 98%: Register execution policy exception for mint 100%: Build succeeded mkdir -p /usr/local/bin cp -f .build/release/mint /usr/local/bin/mint cp: .build/release/mint: No such file or directory make: *** [install] Error 1 Mint on master took 45s
これに関してissueも立っていてそれに対してPRも出ていますがマージされるまで他の方法で導入した方が良いかもしれません。
PRは以下
基本的な使い方
helpコマンドがありますので説明が必要そうなものだけ抜粋します。runコマンドはインストールと実行を合わせてやってくれます。listコマンドでインストールしたツールを一覧で見れます
bootstrapコマンドでMintfileに記述したパッケージをグローバルなくローカルにインストールできます。パッケージのインストールに失敗することもあると思うのでその時は—verboseオプションを付与するのが良さそうです。
mint help Usage: mint <command> [options] Run and install Swift Package Manager executables Commands: run Install and then run a package install Install a package. If the version is already installed no action will be taken uninstall Uninstall a package by name list List all the currently installed packages. Globally linked packages are marked with * bootstrap Installs all the packages in a Mintfile which Prints the full path to the installed executable help Prints help information version Prints the current version of this app
以下のようなコマンドでツールをインストールします。アンインストール時も形式は同じです。
mint install パッケージ名(name/repo)@バージョン
任意のバージョンの実行はrunコマンドを使用します。
mint run name/repo@0version repo_name
swift 5.3の環境でSwiftLintのinstallに失敗する
MintのリポジトリのREADME.mdの冒頭に記載してあるSwiftLIntを導入してみます.
mint install realm/[email protected]
しかし、自分の環境起因でインストールに何度かこけました。swiftlintの.swift_versionに指定されているバージョンと異なるのでインストールに失敗しました。swiftenvでswiftのバージョンを更新します。
? Finding latest version of SwiftLint ? Cloning SwiftLint 0.40.3 ? Resolving package swiftenv: version `5.1' (set by /private/var/folders/d6/wdqrmkd53j728wfxk_xs1snr0000gq/T/mint/github.com_realm_SwiftLint/.swift-version) is not installed ? Encountered error during "swift package resolve". Use --verbose to see full output ? Failed to resolve SwiftLint 0.40.3 with SPM
エラー出力が変わりました。
mint run realm/[email protected] ? Cloning SwiftLint 0.40.3 ? Resolving package ? Building package [1/12] Compiling SourceKit SourceKit.m [2/12] Compiling Clang_C Clang_C.m [3/12] Compiling writer.c [4/12] Compiling reader.c [5/12] Compiling parser.c [6/12] Compiling api.c [7/12] Compiling emitter.c [8/12] Compiling scanner.c [9/13] Compiling SwiftyTextTable TextTable.swift [10/13] Compiling Commandant Argument.swift [11/13] Compiling Yams Constructor.swift /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Combine.framework/Modules/Combine.swiftmodule/x86_64-apple-macos.swiftinterface:648:1: error: unknown attribute '_hasMissingDesignatedInitializers' @_hasMissingDesignatedInitializers @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) ^ /private/var/folders/d6/wdqrmkd53j728wfxk_xs1snr0000gq/T/mint/github.com_realm_SwiftLint/.build/checkouts/Yams/Sources/Yams/Decoder.swift:349:5: error: failed to load module 'Combine' #if canImport(Combine) ^ ? Encountered error during "swift build -c release -Xswiftc -target -Xswiftc x86_64-apple-macosx10.15". Use --verbose to see full output
mint install realm/[email protected]
しかし、自分の環境起因でインストールに失敗しました。
一度目はswiftlintの.swift_versionに指定されているバージョンが見つからないのでインストールに失敗しました。swiftenvで指定のバージョンをインストールします。.swift-versionファイルがローカルでのswiftのバージョンを指定してくれるのでglobalのバージョンは変更する必要がないです。
$swiftenv install 5.1
インストール後にもう一度同じコマンドを実行します。
? Finding latest version of SwiftLint ? Cloning SwiftLint 0.40.3 ? Resolving package swiftenv: version `5.1' (set by /private/var/folders/d6/wdqrmkd53j728wfxk_xs1snr0000gq/T/mint/github.com_realm_SwiftLint/.swift-version) is not installed ? Encountered error during "swift package resolve". Use --verbose to see full output ? Failed to resolve SwiftLint 0.40.3 with SPM
$ sudo xcode-select -s /Applications/Xcode_11.3.1.app/.app/Contents/Developer $ xcode-select --print-path /Applications/Xcode_11.3.1.app/Contents/Developer
もう一度インストールを試すと今度は成功しました。
mint install realm/[email protected] ? Cloning SwiftLint 0.40.3 ? Resolving package ? Building package ? Installed SwiftLint 0.40.3 ? Linked swiftlint 0.40.3 to /usr/local/bin
mintを通してSwiftLintをインストールした状態で、Build PhasesのRun Scriptを以下のようにします。このあたりのシェルスクリプトはプロジェクトごとに違うと思いますが新規プロジェクトだと以下で動くと思います。
# Type a script or drag a script file from your workspace to insert its path. if which mint >/dev/null; then mint run swiftlint swiftlint autocorrect --format mint run swiftlint swiftlint else echo 'warning: Mint not installed. Please install mint from https://github.com/yonaskolb/Mint' fi
Mintfileを利用したローカルへのインストール
グローバルにインストールしてバージョンを指定することでプロジェクトで利用も出来ますがMintfileを使って利用しているパッケージを一覧できるのもメリットがあると思いますのでやってみます。
Mintfileがないのでmint bootstrapは以下のように失敗します。
mint bootstrap ? Mintfile not found
Mintfile を作成してSwiftLintを指定します。
realm/[email protected]
インストールに成功しました。
❯ mint bootstrap ? Cloning SwiftLint 0.40.3 ? Resolving package ? Building package ? Installed SwiftLint 0.40.3 ? Installed 1/1 package
Build Phasesでmintを利用する時、Mintfileでパッケージを指定している場合はMintfileのあるディレクトリでmintコマンドを実行するようにします。
mint runでツールがインストールされていない場合はインストールも行ってくれますが、macOS向けにビルドしているため、Run Scriptを実行中環境変数SDKROOTにセットされているiOSシミュレータ用のSDKだとエラーが発生する場合がります。その場合はスクリプト実行中のみunsetします。
unset SDKROOT
関連するIssueは以下です。
まとめ
Mintのバージョンも1.0になっておらず、README.mdにもUntil 1.0 is reached, minor versions will be breaking.
と記載があるように問題が起きるかもしれません。それでも開発は活発なのと、必要ならコントリビュートすれば良いと思うので開発の面倒事を解決できそうなツールは意識して導入していきたいと思います。
Mintをプロジェクトで使いだして間もないので使い慣れてる人からするとこれはどうなんだという説明もあるかもしれません。その際は記事のコメントかTwitterにてご連絡いただければと思います。